package com.zhuqi.util;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.zhuqi.user.UserCache;
import org.springframework.util.StringUtils;

import javax.websocket.Session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Websocket工具类
 * 记录当前在线的链接对链接进行操作
 */
public class WebsocketUtil {

	/**
	 * 记录当前在线的Session
	 */
	private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();

	/**
	 * 判断当前回话是否进行登陆
	 */
	private static final Map<String, Boolean> ONLINE_SESSION_LOGGING_FLAG = new ConcurrentHashMap<>();

	/**
	 * 登陆的用户
	 */
	private static final Map<String, UserCache> SESSION_USER_CACHE = new ConcurrentHashMap<>();
	public static final String sessionKey = "deviceId";

	/**
	 * 添加session
	 *
	 * @param userId sessionID
	 * @param session session
	 */
	public static void addSession(String userId, Session session) {
		// 此处只允许一个用户的session链接。一个用户的多个连接，我们视为无效。
		ONLINE_SESSION.putIfAbsent(userId, session);
		ONLINE_SESSION_LOGGING_FLAG.putIfAbsent(userId, Boolean.FALSE);
	}

	/**
	 * 关闭session
	 *
	 * @param userId sessionId
	 */
	public static void removeSession(String userId) {
		if (StrUtil.isBlank(userId)) {
			saveDeleteSession();
			return;
		}
		ONLINE_SESSION.remove(userId);
		ONLINE_SESSION_LOGGING_FLAG.remove(userId);
		SESSION_USER_CACHE.remove(userId);
	}

	/**
	 * 安全删除关闭的连接
	 */
	private static void saveDeleteSession() {
		Set<Map.Entry<String, Session>> entries1 = ONLINE_SESSION.entrySet();
		Iterator<Map.Entry<String, Session>> onlineSessionIterator = entries1.iterator();
		ArrayList<String> sessionIds = new ArrayList<>();
		while (onlineSessionIterator.hasNext()) {
			Map.Entry<String, Session> next = onlineSessionIterator.next();
			if (next.getValue() == null) {
				sessionIds.add(next.getKey());
				onlineSessionIterator.remove();
			}
		}

		Set<Map.Entry<String, Boolean>> entries2 = ONLINE_SESSION_LOGGING_FLAG.entrySet();
		Iterator<Map.Entry<String, Boolean>> loggingFlagIterator = entries2.iterator();
		while (loggingFlagIterator.hasNext()) {
			Map.Entry<String, Boolean> next = loggingFlagIterator.next();
			if (sessionIds.contains(next.getKey())) {
				loggingFlagIterator.remove();
			}
		}

		Set<Map.Entry<String, UserCache>> entries3 = SESSION_USER_CACHE.entrySet();
		Iterator<Map.Entry<String, UserCache>> sessionUserCacheiterator = entries3.iterator();
		while (sessionUserCacheiterator.hasNext()) {
			Map.Entry<String, UserCache> next = sessionUserCacheiterator.next();
			if (sessionIds.contains(next.getKey())) {
				loggingFlagIterator.remove();
			}
		}
	}

	/**
	 * 给单个用户推送消息
	 *
	 * @param session session
	 * @param message 消息
	 */
	public static void sendMessage(Session session, String message) {
		if (session == null) {
			return;
		}
		// 加锁 防止：The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
		// 并且不能使用 getAsyncRemote 来发送
		synchronized (session) {
			// 同步
			// RemoteEndpoint.Async async = session.getAsyncRemote();
			// async.sendText(message);
			try {
				session.getBasicRemote().sendText(message);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}

	/**
	 * 向所有在线人发送消息
	 *
	 * @param message 消息
	 */
	public static void sendMessageForAll(String message) {
		//jdk8 新方法
		ONLINE_SESSION.forEach((sessionId, session) -> {
			if (session.isOpen()) {
				sendMessage(session, message);
			}
		});
	}

	/**
	 * 根据用户ID发送消息
	 *
	 * @param result
	 */
	public static void sendMessage(String sessionId, AjaxResult result) {
		sendMessage(sessionId, JSON.toJSONString(result));
	}

	/**
	 * 根据用户ID发送消息
	 *
	 * @param message
	 */
	public static void sendMessage(String sessionId, String message) {
		Session session = ONLINE_SESSION.get(sessionId);
		//判断是否存在该用户的session，判断是否还在线
		if (session == null || !session.isOpen()) {
			return;
		}
		sendMessage(session, message);
	}

	/**
	 * 根据ID获取Session
	 *
	 * @param sessionId sessionId
	 */
	public static Session getSession(String sessionId) {
		return ONLINE_SESSION.get(sessionId);
	}

	/**
	 * 根据传过来的key获取session中的参数
	 * @param key key
	 * @param session session
	 * @return param
	 */
	public static String getParam(String key, Session session) {
		Map map = session.getRequestParameterMap();
		Object userId1 = map.get(key);
		if (userId1 == null) {
			return null;
		}

		String s = userId1.toString();
		s = s.replaceAll("\\[", "").replaceAll("]", "");

		if (!StringUtils.isEmpty(s)) {
			return s;
		}
		return null;
	}

	/**
	 * 判断当前回话有没有登陆
	 * @param id
	 */
	public static Boolean isLogging(String id) {
		return ONLINE_SESSION_LOGGING_FLAG.get(id);
	}

	/**
	 * 添加用户到缓存 map
	 * @param userName 用户名
	 * @param session session
	 */
	public static void addUseCache(String userName, String password, Session session) {
		UserCache userCache = new UserCache();
		userCache.setName(userName);
		userCache.setPassword(password);
		SESSION_USER_CACHE.putIfAbsent(session.getId(), userCache);
	}

	/**
	 * 获取当前会话的用户
	 * @param id sessionId
	 */
	public static UserCache getCurrentUser(String id) {
		return SESSION_USER_CACHE.get(id);

	}

	/**
	 * 修改登陆标识
	 * @param session session
	 */
	public static void updateLoggingStatus(Session session, Boolean tag) {
		ONLINE_SESSION_LOGGING_FLAG.put(session.getId(), tag);
	}

	/**
	 * 根据当前用户名获取用户会话
	 * @param userName 用户名
	 * @return Session
	 */
	public static Session getUserSession(String userName) {
		Set<Map.Entry<String, UserCache>> entries = SESSION_USER_CACHE.entrySet();
		for (Map.Entry<String, UserCache> entry : entries) {
			String key = entry.getKey();
			UserCache value = entry.getValue();
			if (value.getName().equals(userName)) {
				return ONLINE_SESSION.get(key);
			}
		}
		return null;
	}
}
